home *** CD-ROM | disk | FTP | other *** search
- _STRUCTURED PROGRAMMING COLUMN_
- by Jeff Duntemann
-
-
- [LISTING ONE]
-
- TITLE('COMPUTE MONTHLY PAYMENTS')
- PAYMENT PROGRAM
- INCLUDE('\CLARION\STD_KEYS.CLA') !STANDARD KEYCODE EQUATES
-
- SCREEN SCREEN HLP('PAYMENT'),HUE(7,0,0)
- ROW(4,25) PAINT(13,32),HUE(7,1)
- COL(25) STRING('<201,205{30},187>')
- ROW(5,25) REPEAT(3);STRING('<186,0{30},186>') .
- ROW(8,25) STRING('<204,205{30},185>')
- ROW(9,25) REPEAT(7);STRING('<186,0{30},186>') .
- ROW(16,25) STRING('<200,205{30},188>')
- ROW(6,28) STRING('CALCULATE MONTHLY PAYMENTS')
- ROW(13,32) STRING('Payment :')
- ROW(15,30) STRING('Press Ctrl-Esc to Exit')
- ROW(9,32) STRING('Principal:')
- COL(44) ENTRY(@N7),USE(AMOUNT),INS,NUM
- ROW(10,32) STRING('Rate {5}:')
- COL(44) ENTRY(@N7.3),USE(RATE),INS,NUM
- ROW(11,32) STRING('Years :')
- COL(49) ENTRY(@N2),USE(YEARS),INS,NUM
- PAYMENT ROW(13,42) STRING(@N9.2)
- .
- AMOUNT DECIMAL(7) !PRINCIPAL AMOUNT
- RATE DECIMAL(7,3) !ANNUAL PERCENTAGE RATE
- YEARS DECIMAL(3) !TERM IN YEARS
- MONTHS DECIMAL(3) !TERM IN MONTHS
- MON_RATE REAL !MONTHLY RATE
- TEMP REAL !INTERMEDIATE VALUE
-
- CODE !START THE CODE SECTION
- ALERT(CTRL_ESC) !ENABLE THE CTRL-ESC KEY
- HELP('PAYMENT') !OPEN THE HELP FILE
- OPEN(SCREEN) !DISPLAY THE SCREEN LAYOUT
- LOOP !LOOP THROUGH THE FIELDS
- ACCEPT !GET A FIELD FROM THE KEYBOARD
- IF KEYCODE() = CTRL_ESC THEN RETURN. !EXIT ON CTRL-ESC
-
- IF AMOUNT * RATE * YEARS <> 0 !WHEN ALL FIELDS ARE ENTERED:
- MONTHS = YEARS * 12 !COMPUTE MONTHS
- MON_RATE = RATE / 1200 !COMPUTE MONTHLY RATE
- TEMP = 1 / ((1 + MON_RATE) ^ MONTHS) !COMPUTE MONTHLY PAYMENT
- PAYMENT = AMOUNT * (MON_RATE / (1 - TEMP))
- ELSE !OTHERWISE:
- PAYMENT = 0 ! SET MONTHLY PAYMENT TO ZERO
- . !END THE IF STATEMENT
- IF FIELD() = ?YEARS !AFTER THE LAST FIELD
- SELECT(?AMOUNT) ! SELECT THE FIRST FIELD
- . . !END THE IF AND LOOP STATEMENTS
-
-
-
- [LISTING TWO]
-
- { By Jeff Duntemann -- From DDJ for October 1991 }
-
- UNIT Mortgage;
-
- INTERFACE
-
- TYPE
- Payment = RECORD { One element in the amort. table. }
- PayPrincipal : Real;
- PayInterest : Real;
- PrincipalSoFar : Real;
- InterestSoFar : Real;
- ExtraPrincipal : Real;
- Balance : Real;
- END;
- PaymentArray = ARRAY[1..2] OF Payment; { Dynamic array! }
- PaymentPointer = ^PaymentArray;
-
- PMortgage = ^TMortgage;
- TMortgage =
- OBJECT
- Periods : Integer; { Number of periods in mortgage }
- PeriodsPerYear : Integer; { Number of periods in a year }
- Principal : Real; { Amount of principal in cents }
- Interest : Real; { Percentage of interest per *YEAR*}
-
- MonthlyPI : Real; { Monthly payment in cents }
- Payments : PaymentPointer; { Array holding payments }
- PaymentSize : LongInt; { Size in bytes of payments array }
-
- CONSTRUCTOR Init(StartPrincipal : Real;
- StartInterest : Real;
- StartPeriods : Integer;
- StartPeriodsPerYear : Integer);
- PROCEDURE SetNewInterestRate(NewRate : Real);
- PROCEDURE Recalc;
- PROCEDURE GetPayment(PaymentNumber : Integer;
- VAR ThisPayment : Payment);
- PROCEDURE ApplyExtraPrincipal(PaymentNumber : Integer;
- Extra : Real);
- PROCEDURE RemoveExtraPrincipal(PaymentNumber : Integer);
- DESTRUCTOR Done;
- END;
-
- IMPLEMENTATION
- FUNCTION CalcPayment(Principal,InterestPerPeriod : Real;
- NumberOfPeriods : Integer) : Real;
- VAR
- Factor : Real;
- BEGIN
- Factor := EXP(-NumberOfPeriods * LN(1.0 + InterestPerPeriod));
- CalcPayment := Principal * InterestPerPeriod / (1.0 - Factor)
- END;
-
- CONSTRUCTOR TMortgage.Init(StartPrincipal : Real;
- StartInterest : Real;
- StartPeriods : Integer;
- StartPeriodsPerYear : Integer);
- VAR
- I : Integer;
- InterestPerPeriod : Real;
- BEGIN
- { Set up all the initial state values: }
- Principal := StartPrincipal;
- Interest := StartInterest;
- Periods := StartPeriods;
- PeriodsPerYear := StartPeriodsPerYear;
- { Here we calculate the size that the payment array will occupy. }
- { We retain this because the number of payments may change...and }
- { we'll need to dispose of the array when the object is ditched: }
- PaymentSize := SizeOf(Payment) * Periods;
-
- { Allocate payment array on the heap: }
- GetMem(Payments,PaymentSize);
-
- { Initialize extra principal fields of payment array: }
- FOR I := 1 TO Periods DO
- Payments^[I].ExtraPrincipal := 0;
- Recalc; { Calculate the amortization table }
- END;
-
- PROCEDURE TMortgage.SetNewInterestRate(NewRate : Real);
- BEGIN
- Interest := NewRate;
- Recalc;
- END;
-
- { This method calculates the amortization table for the mortgage. }
- { The table is stored in the array pointed to by Payments. }
-
- PROCEDURE TMortgage.Recalc;
- VAR
- I : Integer;
- RemainingPrincipal : Real;
- PaymentCount : Integer;
- InterestThisPeriod : Real;
- InterestPerPeriod : Real;
- HypotheticalPrincipal : Real;
- BEGIN
- InterestPerPeriod := Interest/PeriodsPerYear;
- MonthlyPI := CalcPayment(Principal,
- InterestPerPeriod,
- Periods);
- { Round the monthly to cents: }
- MonthlyPI := int(MonthlyPI * 100.0 + 0.5) / 100.0;
-
- { Now generate the amortization table: }
- RemainingPrincipal := Principal;
- PaymentCount := 0;
- FOR I := 1 TO Periods DO
- BEGIN
- Inc(PaymentCount);
- { Calculate the interest this period and round it to cents: }
- InterestThisPeriod :=
- Int((RemainingPrincipal * InterestPerPeriod) * 100 + 0.5) / 100.0;
- { Store values into payments array: }
- WITH Payments^[PaymentCount] DO
- BEGIN
- IF RemainingPrincipal = 0 THEN { Loan's been paid off! }
- BEGIN
- PayInterest := 0;
- PayPrincipal := 0;
- Balance := 0;
- END
- ELSE
- BEGIN
- HypotheticalPrincipal :=
- MonthlyPI - InterestThisPeriod + ExtraPrincipal;
- IF HypotheticalPrincipal > RemainingPrincipal THEN
- PayPrincipal := RemainingPrincipal
- ELSE
- PayPrincipal := HypotheticalPrincipal;
- PayInterest := InterestThisPeriod;
- RemainingPrincipal :=
- RemainingPrincipal - PayPrincipal; { Update running balance }
- Balance := RemainingPrincipal;
- END;
- { Update the cumulative interest and principal fields: }
- IF PaymentCount = 1 THEN
- BEGIN
- PrincipalSoFar := PayPrincipal;
- InterestSoFar := PayInterest;
- END
- ELSE
- BEGIN
- PrincipalSoFar :=
- Payments^[PaymentCount-1].PrincipalSoFar + PayPrincipal;
- InterestSoFar :=
- Payments^[PaymentCount-1].InterestSoFar + PayInterest;
- END;
- END; { WITH }
- END; { FOR }
- END; { TMortgage.Recalc }
-
- PROCEDURE TMortgage.GetPayment(PaymentNumber : Integer;
- VAR ThisPayment : Payment);
- BEGIN
- ThisPayment := Payments^[PaymentNumber];
- END;
-
- PROCEDURE TMortgage.ApplyExtraPrincipal(PaymentNumber : Integer;
- Extra : Real);
- BEGIN
- Payments^[PaymentNumber].ExtraPrincipal := Extra;
- Recalc;
- END;
-
- PROCEDURE TMortgage.RemoveExtraPrincipal(PaymentNumber : Integer);
- BEGIN
- Payments^[PaymentNumber].ExtraPrincipal := 0.0;
- Recalc;
- END;
-
- DESTRUCTOR TMortgage.Done;
- BEGIN
- FreeMem(Payments,PaymentSize);
- END;
-
- END. { MORTGAGE }